/**
 * 事件处理器管理系统
 * 用于管理和调度各种事件的处理函数
 */
class HandlerManager {
  constructor() {
    this.events = new Map();
    
    this.sortedCache = new Map();
  }

  /**
   * 添加事件处理器
   * @param {Object} cfg - 配置对象
   * @param {string} cfg.ns - 命名空间
   * @param {Function} cfg.fn - 处理函数
   * @param {Object} cfg.self - 上下文对象
   * @param {number} cfg.priority - 优先级（数字越小优先级越高）
   * @param {string} cfg.key - 事件键名
   * @param {string} cfg.event - 事件名（key的别名）
   * @returns {boolean} 是否添加成功
   */
  add(cfg) {
    const { ns, fn, self, priority = 500 } = cfg;
    const key = cfg.key ? cfg.key : (cfg.event ? cfg.event : '');

    // 参数验证
    if (!key || typeof key !== 'string') {
      logger.error('[Handler][Add]: 事件键名无效');
      return false;
    }

    if (typeof fn !== 'function') {
      logger.error(`[Handler][Add]: [${ns}][${key}] 处理函数必须是函数类型`);
      return false;
    }

    if (!ns) {
      logger.error(`[Handler][Add]: [${key}] 缺少命名空间`);
      return false;
    }

    // 先删除同命名空间的旧处理器
    this.del(ns, key);

    logger.mark(`[Handler][Reg]: [${ns}][${key}]`);

    // 获取或创建事件处理器数组
    if (!this.events.has(key)) {
      this.events.set(key, []);
    }

    const handlers = this.events.get(key);
    
    // 创建处理器对象
    const handler = {
      priority,
      fn,
      ns,
      self,
      key
    };

    // 使用二分查找找到插入位置，保持有序
    const insertIndex = this._findInsertIndex(handlers, priority);
    handlers.splice(insertIndex, 0, handler);

    // 标记该key的排序状态为已排序
    this.sortedCache.set(key, true);

    return true;
  }

  /**
   * 删除事件处理器
   * @param {string} ns - 命名空间
   * @param {string} key - 事件键名（可选，不提供则删除该命名空间下所有处理器）
   * @returns {number} 删除的处理器数量
   */
  del(ns, key = '') {
    if (!ns) {
      logger.error('[Handler][Del]: 缺少命名空间参数');
      return 0;
    }

    // 如果没有指定key，删除该命名空间下的所有处理器
    if (!key) {
      let deletedCount = 0;
      for (const [eventKey] of this.events) {
        deletedCount += this.del(ns, eventKey);
      }
      return deletedCount;
    }

    // 获取指定key的处理器数组
    const handlers = this.events.get(key);
    if (!handlers || handlers.length === 0) {
      return 0;
    }

    // 过滤掉要删除的处理器
    const originalLength = handlers.length;
    const filteredHandlers = handlers.filter(handler => handler.ns !== ns);
    
    const deletedCount = originalLength - filteredHandlers.length;
    
    if (deletedCount > 0) {
      if (filteredHandlers.length === 0) {
        // 如果没有剩余的处理器，删除整个key
        this.events.delete(key);
        this.sortedCache.delete(key);
      } else {
        // 更新处理器数组
        this.events.set(key, filteredHandlers);
      }
      
      logger.debug(`[Handler][Del]: 删除了 [${ns}][${key}] 的 ${deletedCount} 个处理器`);
    }

    return deletedCount;
  }

  /**
   * 调用所有处理器（当前被禁用）
   * @param {string} key - 事件键名
   * @param {Object} e - 事件对象
   * @param {*} args - 额外参数
   */
  async callAll(key, e, args) {
    // 暂时屏蔽调用
    // return this.call(key, e, args, true);
  }

  /**
   * 调用事件处理器
   * @param {string} key - 事件键名
   * @param {Object} e - 事件对象
   * @param {*} args - 额外参数
   * @param {boolean} allHandler - 是否调用所有处理器
   * @returns {*} 处理器返回值
   */
  async call(key, e, args, allHandler = false) {
    const handlers = this.events.get(key);
    
    if (!handlers || handlers.length === 0) {
      logger.debug(`[Handler][Call]: 没有找到 [${key}] 的处理器`);
      return;
    }

    let ret;
    
    // 遍历处理器并执行
    for (const handler of handlers) {
      const { fn, self, ns } = handler;
      let done = true;
      
      // reject函数用于标记处理失败
      const reject = (msg = '') => {
        if (msg) {
          logger.mark(`[Handler][Reject]: [${ns}][${key}] ${msg}`);
        }
        done = false;
      };

      try {
        // 调用处理函数
        ret = await fn.call(self, e, args, reject);
        
        if (done && !allHandler) {
          logger.mark(`[Handler][Done]: [${ns}][${key}]`);
          return ret;
        }
      } catch (error) {
        logger.error(`[Handler][Error]: [${ns}][${key}] 执行出错:`, error);
        
        if (!allHandler) {
          continue;
        }
      }
    }

    return ret;
  }

  /**
   * 检查是否存在指定事件的处理器
   * @param {string} key - 事件键名
   * @returns {boolean} 是否存在处理器
   */
  has(key) {
    return this.events.has(key) && this.events.get(key).length > 0;
  }

  /**
   * 获取指定事件的处理器数量
   * @param {string} key - 事件键名
   * @returns {number} 处理器数量
   */
  count(key) {
    const handlers = this.events.get(key);
    return handlers ? handlers.length : 0;
  }

  /**
   * 获取所有事件键名
   * @returns {string[]} 事件键名数组
   */
  getKeys() {
    return Array.from(this.events.keys());
  }

  /**
   * 清空所有处理器
   */
  clear() {
    this.events.clear();
    this.sortedCache.clear();
    logger.mark('[Handler][Clear]: 已清空所有处理器');
  }

  /**
   * 二分查找插入位置
   * @private
   * @param {Array} handlers - 处理器数组
   * @param {number} priority - 要插入的优先级
   * @returns {number} 插入位置索引
   */
  _findInsertIndex(handlers, priority) {
    let left = 0;
    let right = handlers.length;

    while (left < right) {
      const mid = Math.floor((left + right) / 2);
      if (handlers[mid].priority <= priority) {
        left = mid + 1;
      } else {
        right = mid;
      }
    }

    return left;
  }

  /**
   * 获取处理器统计信息
   * @returns {Object} 统计信息
   */
  getStats() {
    const stats = {
      totalEvents: this.events.size,
      totalHandlers: 0,
      eventDetails: {}
    };

    for (const [key, handlers] of this.events) {
      stats.totalHandlers += handlers.length;
      stats.eventDetails[key] = {
        count: handlers.length,
        handlers: handlers.map(h => ({
          ns: h.ns,
          priority: h.priority
        }))
      };
    }

    return stats;
  }
}

const handlerInstance = new HandlerManager();

const Handler = {
  add: handlerInstance.add.bind(handlerInstance),
  del: handlerInstance.del.bind(handlerInstance),
  callAll: handlerInstance.callAll.bind(handlerInstance),
  call: handlerInstance.call.bind(handlerInstance),
  has: handlerInstance.has.bind(handlerInstance),
  count: handlerInstance.count.bind(handlerInstance),
  getKeys: handlerInstance.getKeys.bind(handlerInstance),
  clear: handlerInstance.clear.bind(handlerInstance),
  getStats: handlerInstance.getStats.bind(handlerInstance)
};

export default Handler;